﻿using Spire.Doc;
using Spire.Doc.Fields;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Diagnostics;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Threading.Tasks;
using System.Windows.Forms;
using WordCompareCore.Models;

namespace WordCompareCore
{
    public partial class Form1 : Form
    {
        private Document docSource = new Document();
        private Document docCompare = new Document();
        List<ParagraphDto> listSourceText = new List<ParagraphDto>();
        List<ComapreParagraphDto> listCompareText = new List<ComapreParagraphDto>();
        List<ComapreParagraphDto> listRepeatParagraphsIndex = new List<ComapreParagraphDto>();
        List<ComapreParagraphDto> listSourceRepeatParagraphs = new List<ComapreParagraphDto>();
        public Form1()
        {
            Control.CheckForIllegalCrossThreadCalls = false;
            InitializeComponent();
            InitData();
        }

        private void InitData()
        {
            txtTextNumbers.Value = 20;
            txtTextNumbers.Minimum = 1;
            txtRepeatPercent.Value = 80;
        }
        private void LoadSourceFileParagraphs()
        {
            listSourceText.Clear();
            for (var i = 0; i < docSource.Sections.Count; i++)
            {
                for (var j = 0; j < docSource.Sections[i].Paragraphs.Count; j++)
                {
                    var paragraphs = docSource.Sections[i].Paragraphs[j];
                    if (paragraphs.Text.Length >= txtTextNumbers.Value)
                    {
                        listSourceText.Add(new ParagraphDto(j, paragraphs.Text, i));
                    }
                }
            }
        }
        private void LoadCompareFileParagraphs(string compareFilePath)
        {
            docCompare.LoadFromFile(compareFilePath);
            for (var i = 0; i < docCompare.Sections.Count; i++)
            {
                for (var j = 0; j < docCompare.Sections[i].Paragraphs.Count; j++)
                {
                    var paragraphs = docCompare.Sections[i].Paragraphs[j];
                    if (paragraphs.Text.Length >= txtTextNumbers.Value)
                        listCompareText.Add(new ComapreParagraphDto(j, paragraphs.Text, i, compareFilePath));
                }
            }
        }
        private void OverwriteCompareFile(int sectionIndex,int paragraphIndex,string fileName,decimal percent,string repeatText,string sourceText,out Color paragraphOriginColor)
        {
            Document docOverwrite = new Document(fileName);
            paragraphOriginColor = docOverwrite.Sections[sectionIndex].Paragraphs[paragraphIndex].Format.BackColor;
            if (chkAutoMarkRepeat.Checked)
            {
                docOverwrite.Sections[sectionIndex].Paragraphs[paragraphIndex].Format.BackColor = Color.Red;
            }
            if (chkAutoAddBookmark.Checked)
            {
                repeatText = repeatText.Length > 10 ? repeatText.Substring(0, 10) : repeatText;
                docOverwrite.Sections[sectionIndex].Paragraphs[paragraphIndex].AppendBookmarkStart($"【重复率{(percent * 100).ToString("0.00")}】{repeatText}");
                docOverwrite.Sections[sectionIndex].Paragraphs[paragraphIndex].AppendBookmarkEnd($"【重复率{(percent * 100).ToString("0.00")}】{repeatText}");
                Comment comment = new Comment(docOverwrite);
                comment.Format.Author = "源文档该段落内容：";
                comment.Body.AddParagraph().AppendText(sourceText);

                docOverwrite.Sections[sectionIndex].Paragraphs[paragraphIndex].ChildObjects.Add(comment);
            }
            if (chkAutoAddBookmark.Checked|| chkAutoMarkRepeat.Checked)
            {
                docOverwrite.SaveToFile(fileName);
            }
        }
        private void OverwriteSourceFile(int sectionIndex, int paragraphIndex, string repeatText, out Color paragraphOriginColor)
        {
            paragraphOriginColor = docSource.Sections[sectionIndex].Paragraphs[paragraphIndex].Format.BackColor;
            if (chkAutoMarkRepeat.Checked)
            {
                docSource.Sections[sectionIndex].Paragraphs[paragraphIndex].Format.BackColor = Color.Red;
            }
            if (chkAutoAddBookmark.Checked)
            {
                repeatText = repeatText.Length > 10 ? repeatText.Substring(0, 10) : repeatText;
                docSource.Sections[sectionIndex].Paragraphs[paragraphIndex].AppendBookmarkStart($"【重复】{repeatText}");
                docSource.Sections[sectionIndex].Paragraphs[paragraphIndex].AppendBookmarkEnd($"【重复】{repeatText}");
            }
            if (chkAutoAddBookmark.Checked || chkAutoMarkRepeat.Checked)
            {
                docSource.SaveToFile(lblSourcePath.Text);
            }
        }
        private void Compare()
        {
            listRepeatParagraphsIndex.Clear();
            decimal comparePercent = txtRepeatPercent.Value / (decimal)100;
            int compareTotalNumbers = 0;
            Color color=Color.White;
            foreach (var item in listSourceText)
            {
                int index = listSourceText.IndexOf(item)+1;

                rchTextProccess.AppendText($"开始分析源文档第{index}段...");
                rchTextProccess.AppendText(Environment.NewLine);
                
                foreach (var childItem in listCompareText)
                {
                    compareTotalNumbers++;
                    progressBar1.Value += 1;
                    decimal percent = LevenshteinDistance.Instance.LevenshteinDistancePercent(item.Text, childItem.Text);
                    if (percent >= comparePercent)
                    {
                        var newRepeatTextItem = new ComapreParagraphDto(childItem.Index, childItem.Text, childItem.SectionIndex, childItem.CompareFileName, item.Text);
                        if (!listSourceRepeatParagraphs.Any(m=>m.SectionIndex==item.SectionIndex&&m.Index==item.Index))
                        {
                            var newSourceRepeatTextItem = new ComapreParagraphDto(item.Index, item.Text, item.SectionIndex);
                            OverwriteSourceFile(item.SectionIndex, item.Index, item.Text, out color);
                            newSourceRepeatTextItem.ParagraphOriginColor = color;
                            listSourceRepeatParagraphs.Add(newSourceRepeatTextItem);
                            AddRepeatTextToListBox(newSourceRepeatTextItem);
                        }
                        
                        OverwriteCompareFile(childItem.SectionIndex, childItem.Index, childItem.CompareFileName, percent, childItem.Text, item.Text,out color);
                        newRepeatTextItem.ParagraphOriginColor = color;
                        listRepeatParagraphsIndex.Add(newRepeatTextItem);
                        rchTextProccess.AppendText($"发现第{index}段在【{Path.GetFileName(childItem.CompareFileName)}】文件中出现重复。");
                        rchTextProccess.AppendText(Environment.NewLine);
                        
                    }
                }

            }

            rchTextProccess.AppendText($"全部分析完成！");
            rchTextProccess.AppendText(Environment.NewLine);
        }

        private void btnSltSourceFile_Click(object sender, EventArgs e)
        {
            lblSourcePath.Text = ChooseFile();
            if (File.Exists(lblSourcePath.Text))
            {
                docSource.LoadFromFile(lblSourcePath.Text);
                LoadSourceFileParagraphs();
            }
        }

        private string ChooseFile()
        {
            var diaResult = openFileDialog1.ShowDialog();
            if (diaResult==DialogResult.OK)
            {
                if (IsFileInUse(openFileDialog1.FileName))
                {
                    MessageBox.Show("该文档正在被其它程序占用，无法加载。");
                    return "";
                }
                return openFileDialog1.FileName;
            }
            else
            {
                return "";
            }
        }

        private void btnSltCompare_Click(object sender, EventArgs e)
        {
            string compareFile = ChooseFile();
            if (File.Exists(compareFile)&&!listCompareDocs.Items.Contains(compareFile))
            {
                listCompareDocs.Items.Add(compareFile);
                LoadCompareFileParagraphs(compareFile);
            }
        }

        private void OpenDoc(string path)
        {
            Process process = new Process();
            ProcessStartInfo processStartInfo = new ProcessStartInfo(path);
            process.StartInfo = processStartInfo;
            process.StartInfo.UseShellExecute = true;
            process.Start();
        }
        private void btnStartCompare_Click(object sender, EventArgs e)
        {
            StartCompare();
        }

        private void StartCompare()
        {
            rchTextProccess.Focus();
            Task.Run(new Action(() =>
            {
                flowLayoutPanel1.Controls.Clear();
                flowLayoutPanel2.Controls.Clear();
                progressBar1.Value = 0;
                progressBar1.Maximum = listSourceText.Count * listCompareText.Count;
                rchTextProccess.Clear();
                listSourceRepeatParagraphs.Clear();
                Compare();
            }));
        }

        private void AddRepeatTextToListBox(ComapreParagraphDto comapreParagraphDto)
        {
            var txtAreaSource = new RichTextBox();
            txtAreaSource.BorderStyle = BorderStyle.None;
            txtAreaSource.BackColor = Color.White;
            txtAreaSource.ForeColor = Color.Black;
            txtAreaSource.Font = new Font("Microsoft YaHei UI", 9);
            txtAreaSource.ReadOnly = true;
            txtAreaSource.Margin = new Padding(0,2,0,2);
            txtAreaSource.Cursor = Cursors.Hand;
            txtAreaSource.Text = $"{comapreParagraphDto.Text}";
            txtAreaSource.Width = flowLayoutPanel1.Width;
            txtAreaSource.Enabled = true;
            txtAreaSource.Tag= lblSourcePath.Text;
            txtAreaSource.ScrollBars = RichTextBoxScrollBars.None;
            txtAreaSource.ContentsResized += TxtAreaSource_ContentsResized;
            //txtAreaSource.MouseHover += TxtAreaSource_MouseHover;
            //txtAreaSource.MouseLeave += TxtAreaSource_MouseLeave;
            txtAreaSource.Click += TxtAreaSource_Click;
            txtAreaSource.DoubleClick += TxtAreaSource_DoubleClick;
            flowLayoutPanel1.Invoke(new Action(() =>
            {
                flowLayoutPanel1.Controls.Add(txtAreaSource);
            }));

        }

        private void TxtAreaSource_ContentsResized(object sender, ContentsResizedEventArgs e)
        {
            var txtArea = (RichTextBox)sender;
            txtArea.Height = e.NewRectangle.Height + 5;
        }

        private void TxtAreaSource_DoubleClick(object sender, EventArgs e)
        {
            var txtArea = (RichTextBox)sender;
            OpenDoc(txtArea.Tag.ToString());
        }

        private void ResetSourceRichTextBoxStyle(FlowLayoutPanel flowLayoutPanel)
        {
            foreach (Control item in flowLayoutPanel.Controls)
            {
                if (item is RichTextBox)
                {
                    ((RichTextBox)item).SelectAll();
                    ((RichTextBox)item).SelectionColor = Color.Black;
                    ((RichTextBox)item).BackColor = Color.White;
                    ((RichTextBox)item).ForeColor = Color.Black;
                }
            }
        }

        private void TxtAreaSource_Click(object sender, EventArgs e)
        {
            var txtArea = (RichTextBox)sender;
            ResetSourceRichTextBoxStyle((FlowLayoutPanel)txtArea.Parent);
            //txtArea.BackColor = Color.LightYellow;
            //txtArea.ForeColor = Color.Red;
            AppendRepeatTxtToShowList(txtArea.Text, txtArea);
        }

        private void TxtAreaSource_MouseLeave(object sender, EventArgs e)
        {
            var lbl = (RichTextBox)sender;
            if (!lbl.Focused)
            {
                lbl.Cursor = Cursors.Default;
                lbl.BackColor = Color.White;
                lbl.ForeColor = Color.Black;
            }
            
        }

        private void TxtAreaSource_MouseHover(object sender, EventArgs e)
        {
            var lbl = (RichTextBox)sender;
            lbl.Cursor = Cursors.Hand;
            lbl.BackColor = Color.LightYellow;
            lbl.ForeColor = Color.Red;
        }

        private void AppendRepeatTxtToShowList(string sourceTxt,RichTextBox sourceTextBox)
        {
            flowLayoutPanel2.Controls.Clear();
            var list = listRepeatParagraphsIndex.Where(m => m.SourceText == sourceTxt).Distinct().ToList();
            selectedIndex.Clear();
            foreach (var item in list)
            {
                var txtAreaSource = new RichTextBox();
                txtAreaSource.BorderStyle = BorderStyle.None;
                txtAreaSource.BackColor = Color.White;
                txtAreaSource.ForeColor = Color.Black;
                txtAreaSource.Font = new Font("Microsoft YaHei UI", 9);
                txtAreaSource.ReadOnly = true;
                txtAreaSource.Margin = new Padding(0, 2, 0, 2);
                txtAreaSource.Cursor = Cursors.Hand;
                txtAreaSource.Text = $"【{Path.GetFileName(item.CompareFileName)}】{Environment.NewLine}{item.Text}";
                txtAreaSource.Width = flowLayoutPanel2.Width;
                txtAreaSource.Enabled = true;
                txtAreaSource.Tag = item.CompareFileName;
                txtAreaSource.ScrollBars = RichTextBoxScrollBars.None;
                txtAreaSource.ContentsResized += TxtAreaSource_ContentsResized;
                //txtAreaSource.MouseHover += TxtAreaSource_MouseHover;
                //txtAreaSource.MouseLeave += TxtAreaSource_MouseLeave;
                txtAreaSource.DoubleClick += TxtAreaSource_DoubleClick;
                //txtAreaSource.Click += TxtAreaRepeat_Click;
                RichTextBoxWordDiffCompare(sourceTextBox, txtAreaSource, $"【{Path.GetFileName(item.CompareFileName)}】{Environment.NewLine}".Length);
                flowLayoutPanel2.Invoke(new Action(() =>
                {
                    flowLayoutPanel2.Controls.Add(txtAreaSource);
                }));
            }
            RichTextBoxWordDiffSource(sourceTextBox);
        }

        List<int> selectedIndex = new List<int>();
        private void RichTextBoxWordDiffSource(RichTextBox richTextBoxSource)
        {
            foreach (var item in selectedIndex)
            {
                richTextBoxSource.SelectionStart = item;
                richTextBoxSource.SelectionLength = 1;
                richTextBoxSource.SelectionColor = Color.Orange;
            }
        }
        private void RichTextBoxWordDiffCompare(RichTextBox richTextBoxSource,RichTextBox richTextBoxCompare,int compareTitleLength)
        {
            for (int i = 0; i < richTextBoxSource.Text.Length; i++)
            {
                for (int j = compareTitleLength; j < richTextBoxCompare.Text.Length; j++)
                {
                    if (richTextBoxSource.Text[i]==richTextBoxCompare.Text[j])
                    {
                        if (!selectedIndex.Contains(i))
                        {
                            selectedIndex.Add(i);
                        }
                        //richTextBoxSource.SelectionStart = i;
                        //richTextBoxSource.SelectionLength = 1;
                        //richTextBoxSource.SelectionColor = Color.Orange;

                        richTextBoxCompare.SelectionStart = j;
                        richTextBoxCompare.SelectionLength = 1;
                        richTextBoxCompare.SelectionColor = Color.Orange;
                    }
                }
            }
        }
        private void TxtAreaRepeat_Click(object sender, EventArgs e)
        {
            var txtArea = (RichTextBox)sender;
            ResetSourceRichTextBoxStyle((FlowLayoutPanel)txtArea.Parent);
            txtArea.BackColor = Color.LightYellow;
            txtArea.ForeColor = Color.Red;
        }
        private void btnDeleteCompareFile_Click(object sender, EventArgs e)
        {
            string fileName = listCompareDocs.SelectedItem.ToString();
            listCompareDocs.Items.Remove(listCompareDocs.SelectedItem);
            listCompareText.RemoveAll(m => m.CompareFileName == fileName);
        }

        private void btnClearAllFlagAndMark_Click(object sender, EventArgs e)
        {
            ClearDocFlagAndMark();
        }

        private void ClearDocFlagAndMark()
        {
            #region 注释原因：有极少段落的底色无法清除
            //if (listSourceRepeatParagraphs.Count>0)
            //{//按重复的段落清除

            //    foreach (var item in listSourceRepeatParagraphs)
            //    {
            //        docSource.Sections[item.SectionIndex].Paragraphs[item.Index].Format.BackColor = item.ParagraphOriginColor;

            //    }
            //}
            //else
            //{

            //    for (int i = 0; i < docSource.Sections.Count; i++)
            //    {
            //        for (int j = 0; j < docSource.Sections[i].Paragraphs.Count; j++)
            //        {
            //            docSource.Sections[i].Paragraphs[j].Format.BackColor = Color.White;
            //        }
            //    }
            //}
            #endregion
            //清除文档所有段落的底色
            for (int i = 0; i < docSource.Sections.Count; i++)
            {
                for (int j = 0; j < docSource.Sections[i].Paragraphs.Count; j++)
                {
                    docSource.Sections[i].Paragraphs[j].Format.BackColor = Color.White;
                }
            }
            docSource.Comments.Clear();
            docSource.Bookmarks.Clear();
            if (!IsFileInUse(lblSourcePath.Text))
            {
                docSource.SaveToFile(lblSourcePath.Text);
            }
            //var compareFiles = listRepeatParagraphsIndex.Select(m => m.CompareFileName).Distinct().ToList();
           
            foreach (var item in listCompareDocs.Items)
            {
                string compareFilePath = item.ToString();
                if (!IsFileInUse(compareFilePath))
                {
                    var docCompare = new Document(compareFilePath);
                    #region 注释原因：有极少段落的底色无法清除
                    //var listParagraphs = listRepeatParagraphsIndex.Where(m => m.CompareFileName == compareFilePath).ToList();
                    //if (listParagraphs.Count>0)
                    //{//按重复的段落清除
                    //    foreach (var item1 in listParagraphs)
                    //    {
                    //        docCompare.Sections[item1.SectionIndex].Paragraphs[item1.Index].Format.BackColor = item1.ParagraphOriginColor;
                    //    }
                    //}
                    //else
                    //{
                    //    for (int i = 0; i < docCompare.Sections.Count; i++)
                    //    {
                    //        for (int j = 0; j < docCompare.Sections[i].Paragraphs.Count; j++)
                    //        {
                    //            docCompare.Sections[i].Paragraphs[j].Format.BackColor = Color.White;
                    //        }
                    //    }
                    //}
                    #endregion

                    //清除文档所有段落的底色
                    for (int i = 0; i < docCompare.Sections.Count; i++)
                    {
                        for (int j = 0; j < docCompare.Sections[i].Paragraphs.Count; j++)
                        {
                            docCompare.Sections[i].Paragraphs[j].Format.BackColor = Color.White;
                        }
                    }
                    docCompare.Comments.Clear();
                    docCompare.Bookmarks.Clear();
                    docCompare.SaveToFile(compareFilePath);
                }
            }
            MessageBox.Show("清除完成。");
        }
        /// <summary>
        /// 判断文件是否正在被使用
        /// </summary>
        /// <param name="fileName"></param>
        /// <returns></returns>
        private bool IsFileInUse(string fileName)
        {
            bool inUse = true;

            FileStream fs = null;
            try
            {

                fs = new FileStream(fileName, FileMode.Open, FileAccess.Read,

                FileShare.None);

                inUse = false;
            }
            catch
            {
            }
            finally
            {
                if (fs != null)

                    fs.Close();
            }
            //true表示正在使用,false没有使用
            return inUse;
        }
    }
}
